package com.ai.web.service.impl;

import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.ai.web.cache.Constants;
import com.ai.web.cache.UserContext;
import com.ai.web.service.BaseService;
import com.ai.web.util.DataUtil;
import com.ai.web.vo.QueryData;
import com.ai.web.vo.UploadFileV;
import com.tiny.persistence.repository.BaseRepo;

public abstract class BaseServiceImpl<T, ID extends Serializable, E> implements BaseService {

	private static Logger logger = Logger.getLogger(LoginOutServiceImpl.class);
	
	private BaseRepo<T, ID> repo;
	
	public BaseServiceImpl(BaseRepo<T, ID> repo) {
		this.repo = repo;
	}
	
	public E saveT(E e) throws Exception {
		try {
			Class<T> clazzT = getClassT();
			T t = clazzT.newInstance();
			BeanUtils.copyProperties(e, t);
			
			// save obj
			T saveT = repo.save(t);
			
			Class<E> clazzE = getClassE();
			E newE = clazzE.newInstance();
			
			BeanUtils.copyProperties(saveT, newE);
			
			return newE;
		} catch (Exception e1) {
			throw new Exception(e1);
		}
		
	}
	
	public E getT(ID id) throws Exception {
		try {
			T t = repo.findOne(id);
			
			Class<E> clazzE = getClassE();
			E getE = clazzE.newInstance();
			
			BeanUtils.copyProperties(t, getE);
			
			return getE;
		} catch (Exception e1) {
			throw new Exception(e1);
		}
	}
	
	public void deleteT(ID id) throws Exception {
		try {
			repo.delete(id);
		} catch (Exception e1) {
			throw new Exception(e1);
		}
	}
	
	public void deleteTs(List<ID> ids) throws Exception {
		
		try {
			String logObjName = null;
			
			List<T> list = new ArrayList<T>();
			for (ID id : ids) {
				Field idField = null;
				Class<T> clazzT = getClassT();
				T t = clazzT.newInstance();
				
				if (logObjName == null) {
					logObjName = t.getClass().getName();
				}
				
				Field[] fields = t.getClass().getDeclaredFields();
				for (Field field : fields) {
					
					javax.persistence.Id idAnno = field.getAnnotation(javax.persistence.Id.class);
					if (idAnno == null) {
						continue;
					} else {
						idField = field;
					}
				}
				
				if (idField != null) {
					idField.setAccessible(true);
					idField.set(t, id);
					list.add(t);
				}
			}
			
			logger.info("[BaseService] deleteTs. T=" + logObjName + " id length=" + ids.size() + " del size=" + list.size());
			
			repo.delete(list);
			
		} catch (Exception e1) {
			throw new Exception(e1);
		}
	}
	
	public QueryData queryListAndCount(Map<String, Object> condition) throws Exception {
		
		try {
			@SuppressWarnings("unchecked")
			List<T> list = (List<T>) repo.getListByCondition(condition);
			
			Class<E> clazzE = getClassE();
			
			List<E> results = DataUtil.buildListVO(list, clazzE);
			
			int totalCount = repo.getCountByCondition(condition);
			
			QueryData qd = new QueryData();
			qd.setTotalCount(totalCount);
			qd.setDataList(results);
			UserContext uc = (UserContext) condition.get(Constants.USER_CONTEXT);
			qd.setPageSize(uc.getPageSize());
			qd.setCurrPage((Integer) condition.get(Constants.KEY_PAGE_FROM));
			qd.build();
			
			return qd;
		} catch (Exception e1) {
			throw new Exception(e1);
		}
	}
	
	public List<?> queryList(Map<String, Object> condition) throws Exception{
	    try {
            @SuppressWarnings("unchecked")
            List<T> list = (List<T>) repo.getListByCondition(condition);
            
            Class<E> clazzE = getClassE();
            
            List<E> results = DataUtil.buildListVO(list, clazzE);
            
            return results;
            
        } catch (Exception e1) {
            throw new Exception(e1);
        }
	}
	
	@SuppressWarnings("unchecked")
	private Class<E> getClassE() {
		return (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[2]; 
	}
	
	@SuppressWarnings("unchecked")
	private Class<T> getClassT() {
		return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
	}
	
	/**
	 * 文件上传
	 */
    public List<UploadFileV> uploadFiles(HttpServletRequest request) throws Exception {
        List<UploadFileV> uploadFileVs = new ArrayList<UploadFileV>();
        
        CommonsMultipartResolver multipartResolver  = new CommonsMultipartResolver(request.getSession().getServletContext());
        if(multipartResolver.isMultipart(request)){
            MultipartHttpServletRequest  multiRequest = (MultipartHttpServletRequest)request;
            
            Iterator<String>  iter = multiRequest.getFileNames();
            while(iter.hasNext()){
                    MultipartFile file = multiRequest.getFile((String)iter.next());
                if(file != null){
                    //文件名称
                    String fileName = new Date().getTime() + file.getOriginalFilename();
                    String path = request.getContextPath()+"/uploadFiles/"+fileName;
                    File localFile = new File(request.getRealPath(path));
                    file.transferTo(localFile);
                    
                    //返回文件上传信息，包括文件名称、文件上传后路径
                    UploadFileV uploadFileV = new UploadFileV();
                    uploadFileV.setOriginalFilename(file.getOriginalFilename());
                    uploadFileV.setFileRealPath(request.getRealPath(path));
                    uploadFileV.setSuccessCode();
                    uploadFileVs.add(uploadFileV);
                }
                
            }
        }
        
        return uploadFileVs;
    }

	
}
